
#include "wgetopt.h"

using namespace std;

wopt::wopt()
{

}
wopt::wopt(char* name_, int opt_type_, int has_arg_, bool* opt_, void (* func_)())
{
    name = name_;
    opt_type = opt_type_;
    has_arg = has_arg_;
    opt = opt_;
    func = func_;
    desc = NULL;
    optarg = NULL;
}
wgetopt::wgetopt()
{
    opts = new wopt[32];
    unopts = new char*[32];
    sz = 0;
    unopts_sz = 0;
}
wgetopt::wgetopt(int maxsz)
{
    opts = new wopt[maxsz];
    unopts = new char*[maxsz];
    sz = 0;
    unopts_sz = 0;
}
wgetopt::~wgetopt()
{
    delete[] opts;
}
int wgetopt::addopt(char* name, int opt_type, int has_arg, bool* opt, void (*func)())
{
    opts[sz] = wopt(name, opt_type, has_arg, opt, func);
    sz++;
    return (sz-1);
}
int wgetopt::addindexarg(int index, void (*func)())
{
    opts[sz] = wopt(NULL, opt_pos, 0, NULL, func);
    opts[sz].index = index;
    sz++;
    return (sz-1);
}
int wgetopt::addflagopt(char *flag, bool* bptr)
{
    opts[sz] = wopt(flag, opt_flag, no_arg, bptr, NULL);
    sz++;
    return (sz-1);
}
void wgetopt::setlastdesc(char* des)
{
    opts[sz-1].desc = des;
}
void wgetopt::toggleopt(wopt* w)
{
    if(w->opt != NULL)  *w->opt ^= true;
    if(w->func != NULL) w->func();
}
void wgetopt::checkarg(char** argv, int *i, int *r)
{
    if(opts[*i].has_arg == req_arg)  {
        opts[*i].optarg = argv[*r+1];
        *r++;
    }
}
//parse cmdline args
void wgetopt::parse(int argc, char** argv)
{
    int i,r,c;
    int argvlen;
    int optlen;
    bool ct;
    //opt parser
    for(r = 0; r < argc; r++) {   //loop thru argv
        ct = false;
        for(i = 0; i < sz; i++)   { //loop thru opts
            if(opts[i].opt_type == opt_flag)    {   //check if opts[i] is opt_flag
                if(argv[r][0] == '-' && argv[r][1] != '-')  {   //check for '-' in start of argv[r]
                    argvlen = strlen(argv[r]);
                    for(c = 1; c < argvlen; c++)    {   //loop thru each char in argv[r]
                        if(argv[r][c] == opts[i].name[0])   {
                            toggleopt(&opts[i]);
                            checkarg(argv, &i, &r);
                            ct = true;
                        }
                    }
                }
            } else if(opts[i].opt_type == opt_long) {   //check if opts[i] is opt_long
                if(argv[r][0] == '-' && argv[r][1] == '-')  {   //check for '--' in argv[r] for long opts
                    argvlen = strlen(argv[r]);
                    optlen = strlen(opts[i].name);
                    if(optlen == (argvlen - 2))   {   //check for matching sizes of argv[r] and opt[i].name
                        if(memcmp(&argv[r][2], &opts[i].name[0], optlen) == 0)    {   //memcmp argv[r][2] opts[i].name[0] for optlen
                            toggleopt(&opts[i]);
                            checkarg(argv, &i, &r);
                            ct = true;
                        }
                    }
                }
            }
        }
        if(!ct) {
            unopts[unopts_sz] = argv[r];
            unopts_sz++;
        } else
            continue;
    }
}
void printusage(wgetopt *o)
{
    cout << "usage: " << o->info->name << " < "
         << o->info->desc << " > " << o->info->vers << endl
         << "loaded commands: " << endl;
    for(int i  = 0; i < o->sz; i++)    {
        if(o->opts[i].desc != NULL)    {
            if(o->opts[i].opt_type == opt_flag)    {
                cout << "   -" << o->opts[i].name[0]
                     << "       " << o->opts[i].desc << endl;
            } else if(o->opts[i].opt_type == opt_long)    {
                cout << "   --" << o->opts[i].name
                     << "       " << o->opts[i].desc << endl;
            } else if(o->opts[i].opt_type == opt_pos)  {
                cout << "   arg #" << o->opts[i].index
                     << "       " << o->opts[i].desc << endl;
            }

        }
    }
}


